package com.gun3y.entity.htmlparser;

import org.apache.commons.lang3.StringUtils;
import org.htmlparser.Node;
import org.htmlparser.NodeFilter;
import org.htmlparser.Tag;
import org.htmlparser.Text;

/**
 * This class accepts all tags that have a sibling acceptable to another filter.
 * End tags are not considered to be siblings of any tag.
 */

public class HasSiblingExFilter implements NodeFilter {

    public enum SiblingType {
	PREVIOUS_SIBLING, NEXT_SIBLING
    }

    /**
     * 
     */
    private static final long serialVersionUID = 967805216756089364L;

    /**
     * The filter to apply to the sibling.
     */
    protected NodeFilter mSiblingTagFilter;

    /**
     * Performs a recursive search up the node heirarchy if <code>true</code>.
     */
    protected boolean mRecursive;

    protected SiblingType siblingType;

    /**
     * Creates a new instance of HasSiblingFilter. With no sibling filter, this
     * would always return <code>false</code> from {@link #accept}.
     */

    public HasSiblingExFilter(NodeFilter filter, boolean mRecursive, SiblingType siblingType) {
	super();
	this.mSiblingTagFilter = filter;
	this.mRecursive = mRecursive;
	this.siblingType = siblingType;

    }

    /**
     * Get the filter used by this HasSiblingFilter.
     * 
     * @return The filter to apply to siblings.
     */
    public NodeFilter getSiblingTagFilter() {
	return mSiblingTagFilter;
    }

    /**
     * Set the filter for this HasSiblingFilter.
     * 
     * @param filter
     *            The filter to apply to siblings in {@link #accept}.
     */
    public void setSiblingTagFilter(NodeFilter filter) {
	mSiblingTagFilter = filter;
    }

    /**
     * Accept tags with a sibling acceptable to the filter.
     * 
     * @param node
     *            The node to check.
     * @return <code>true</code> if the node has an acceptable sibling,
     *         <code>false</code> otherwise.
     */
    public boolean accept(Node node) {

	boolean ret = false;

	Node sibling = node;

	do {
	    /* exclusive textNOde and endTag */
	    do {
		boolean flag = false;
		if (this.siblingType == SiblingType.PREVIOUS_SIBLING) {
		    sibling = sibling.getPreviousSibling();
		}
		else {
		    sibling = sibling.getNextSibling();
		}

		if (sibling == null) {
		    return ret;
		}
		else if (sibling instanceof Text && StringUtils.isNotBlank(((Text) sibling).getText())) {
		    flag = true;
		}
		else if (sibling instanceof Tag && !((Tag) sibling).isEndTag()) {
		    flag = true;
		}
		if (flag) {
		    break;
		}

	    }
	    while (true);

	    ret = getSiblingTagFilter().accept(sibling);

	}
	while (isMRecursive() && !ret);

	return ret;
    }

    public SiblingType getSiblingType() {
	return siblingType;
    }

    public void setSiblingType(SiblingType siblingType) {
	this.siblingType = siblingType;
    }

    public boolean isMRecursive() {
	return mRecursive;
    }

    public void setMRecursive(boolean recursive) {
	mRecursive = recursive;
    }
}
